/**
 * 目标：实现数组对象的所有属性的访问器。
 * 思考：
 * 1. 嵌套数组如何设置访问器？
 * 2. 数组静态方法的调用如何触发访问器？
 */

/**
 * @description 为普通对象的某个属性设置访问器
 * @param {*} obj 
 * @param {*} key 
 * @param {*} value 
 */
function defineReactive(obj, key, value) {
    value = obj[key];
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function () {
            // 在此处收集依赖
            console.log('get:', value);
            return value;
        },
        set: function (newValue) {
            // 在此处通知依赖进行更新
            console.log('set:', newValue);
            value = newValue;
        }
    })
}

/**
 * @description 循环遍历，为普通对象的所有属性设置访问器
 * @param {*} obj 
 */
function walk(obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
        defineReactive(obj, keys[i])
    }
}

function isObject(obj) {
    return obj !== null && typeof obj === 'object'
}

/**
 * @description 为数组对象设置访问器
 * @param {Array.<Array<any>>} items 
 */
function observeArray(items) {
    // 不是对象的值无需设置访问器
    if (!isObject(items)) return;
    // 
    for (let i = 0, l = items.length; i < l; i++) {
        if (Array.isArray(items[i])) {
            // 子项仍然是数组的情况
            observeArray(items[i]) // 递归调用为数组子项设置访问器
        } else {
            // 子项为普通对象的情况
            walk(items[i])
        }
    }
}

//

const arr = [1, 2, { age: 100, name: 'lll' }, [66, 77, { foo: 'hi', bar: 'hello' }]]
observeArray(arr)

const obj1 = arr[2]
console.log(obj1.name);

const obj2 = arr[3][2]
console.log(obj2.foo);

obj2.bar = 'hello world';
console.log(obj2.bar);

// ;//

// // const obj = {
// //     name: 'zs',
// //     age: 18,
// // }

// // walk(obj, 'name')
// // console.log(obj.name);
// // obj.name = 'ls'
// // console.log(obj.name);
// // obj.age = 20
// // console.log(obj.age);

// ;//